<?php
/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/12/25
 * Time: 13:29
 * @link http://www.lmterp.cn
 */

namespace app\admin\controller\wms;

use app\admin\controller\BaseController;
use app\common\library\Tools;
use app\common\model\Orders;
use app\common\model\OrdersDetail;
use app\common\model\OrdersReturn;
use app\common\model\Producer;
use app\common\model\Purchase;
use app\common\model\PurchaseException;
use app\common\model\PurchaseTrack;
use app\common\model\Warehouse;
use app\common\model\WarehouseAllot;
use app\common\model\WarehouseBorrow;
use app\common\service\purchase\PurchaseService;
use think\Db;

/**
 * 收货
 * Class RecvController
 * @package app\admin\controller\wms
 */
class RecvController extends BaseController
{

    /**
     * 待收货采购单
     * @return string
     * @date 2020/12/25
     * @author longli
     */
    public function purchase()
    {
        if(!$this->request->isAjax())
        {
            $this->assign("producer", Producer::getAll());
            $this->assign("is_show_batch", $this->user->hasPermissions("/wms/recv/purchase_batch"));
            return $this->fetch("purchase_index");
        }
        $purchase = Purchase::with(["info", "producer", "warehouse"])
                ->whereIn("order_status", [Purchase::ORDER_STATUS_OUT,
                    Purchase::ORDER_STATUS_SHIPPING, Purchase::ORDER_STATUS_EXCEPTION])
                ->where('warehouse_id', $this->warehouse->warehouse_id);
        $this->searchModel($purchase, [
            'eq' => ['producer_id']
        ]);
        $limit = $this->getPageSize();
        $purchase = $purchase->paginate($limit);
        $this->assign("list", $purchase->getCollection());
        $this->assign("page", $purchase->render());
        return $this->fetch("purchase_lists");
    }

    /**
     * 采购单收货
     * @date 2021/01/19
     * @author longli
     */
    public function purchase_recv()
    {
        // 处理收货逻辑
        if($this->request->isPost())
        {
            // 验证参数
            if(($msg = $this->validatePurchaseRecv()) !== true)
                $this->error($msg, '', ["type" => "recv-fail"]);

            // 组装数据
            $data = [];
            $post = $this->request->post();
            if($post['is_track']) $data['track_num'] = trim($post['po']);
            foreach($post['sku'] as $k => $sku)
            {
                $remark = isset($post['remark'][$k]) ? trim($post['remark'][$k]) : '';
                $eQty = 0;
                // 异常
                if($post['ex_qty'][$k] > 0)
                {
                    $eQty += intval($post['ex_qty'][$k]);
                    $data['exception'][$k] = [
                            "sku" => $sku,
                            "qty" => $eQty,
                            "remark" => $remark,
                            "exe_type" => $post['ex_type'][$k],
                    ];
                    $remark = '';
                }
                $suQty = $post['qty'][$k] == $post['sqty'][$k]
                    ? intval($post['sqty'][$k]) - $eQty
                    : intval($post['qty'][$k]);
                // 成功
                $data['success'][$k] = [
                    'sku' => $sku,
                    'qty' => $suQty,
                    'remark' => $remark,
                ];
            }
            // 执行收货
            if(($msg = PurchaseService::getInstance()->recvByPurId($post['purchase_id'], $data)) !== true)
                $this->error($msg, '', ["type" => "recv-fail"]);
            $this->success("收货成功", '', ["type" => "recv-success"]);
        }
        // 展示收货界面
        $po = $this->request->get("po", '', 'trim');
        if(!($temp = $purchase = PurchaseService::getInstance()->getByPoTrack($po)))
            $this->error("采购单不存在", '', ["type" => "order-not-exist"]);
        $isTrack = false;
        if($purchase instanceof PurchaseTrack)
        {
            $purchase = $purchase->purchase;
            $this->assign("temp", $temp);
            $isTrack = true;
        }
        if($purchase->warehouse_id != $this->warehouse->warehouse_id)
            $this->error("采购单不属于【{$this->warehouse->name}】", '', ["type" => "abnormal-operation"]);
        $this->assign("ex_type", PurchaseException::$EXCEPTION_TYPE);
        $this->assign("purchase", $purchase);
        $this->assign("is_track", $isTrack);
        $this->assign("po", $po);
        // 展示收货界面
        return $this->fetch("purchase_recv");
    }

    /**
     * 验证采购收货
     * @return bool|string
     * @date 2021/01/20
     * @author longli
     */
    private function validatePurchaseRecv()
    {
        $validate = \think\facade\Validate::make([
            'purchase_id'  => 'require',
            'sku'  => 'require|array',
            'qty'  => 'require|array',
            'ex_qty'  => 'require|array',
            'ex_type'  => 'require|array',
        ],[
            'purchase_id.require' => '采购单必传',
            'sku.array' => 'SKU 只能是数组',
            'qty.array' => '数量只能是数组',
            'ex_qty.array' => '异常数量只能是数组',
            'ex_type.array' => '异常类型只能是数组',
        ]);
        $post = $this->request->post();
        if(!$validate->batch()->check($post)) return join(', ', $validate->getError());
        $error = [];
        $purchase = Purchase::field(['purchase_id'])->with(['info' => function($query)
        {
            $query->field(['purchase_id', 'sku', 'qty']);
        }])->where('purchase_id', $post['purchase_id'])->find();
        foreach($post['sku'] as $k => $sku)
        {
            if($post['qty'][$k] < 0) $error[] = "SKU【{$sku}】数量有误";
            if($post['ex_qty'][$k] < 0) $error[] = "SKU【{$sku}】异常数量有误";
            if($post['ex_qty'][$k] > 0 && empty($post['ex_type'][$k])) $error[] = "SKU【{$sku}】异常类型不能为空";
            if($post['ex_qty'][$k] > 0 && !empty($purchase))
            {
                foreach($purchase->info as $info)
                {
                    if($info->sku == $sku && $post['ex_qty'][$k] > $info->qty)
                        $error[] = "SKU【{$sku}】异常数量大于采购数量";
                }
            }
        }
        if(!empty($error)) return join(", ", $error);
        return true;
    }

    /**
     * 采购单批量收货
     * @date 2021/01/19
     * @author longli
     */
    public function purchase_batch()
    {
        $purIds = $this->request->get("ids");
        if(empty($purIds)) $this->error("非法请求");
        foreach(Purchase::with(["info", "track"])
                    ->whereIn("purchase_id", $purIds)
                    ->select() as $k => $purchase)
        {
            if($purchase->warehouse_id != $this->warehouse->warehouse_id) continue;
            // 组装数据
            $data = [];
            foreach($purchase->info as $info)
            {
                $data["success"][] = [
                    "sku" => $info->sku,
                    "qty" => $info->qty,
                    "remark" => "批量收货",
                ];
            }
            // 执行收货
            if(($msg = PurchaseService::getInstance()->recvByPurId($purchase->purchase_id, $data)) !== true)
            {
                $k > 0
                    ? $this->success($msg, '', ["type" => "recv-part-success"])
                    : $this->error($msg, '', ["type" => "recv-fail"]);
            }
            // 更新追踪号
            if(!empty($purchase->track))
            {
                foreach($purchase->track as $track)
                {
                    PurchaseTrack::recv($track->track_num, $purchase->purchase_id);
                }
            }
        }
        $this->success("批量收货成功", '', ["type" => "recv-success"]);
    }

    /**
     * 调拨单收货
     * @return string
     * @date 2020/12/25
     * @author longli
     */
    public function allot()
    {
        if($this->request->isAjax())
        {
            $allot = WarehouseAllot::with(['wout', 'win', 'user'])
                    ->where([
                        ["status", 'eq',WarehouseAllot::ALLOT_STATUS_ING],
                        ['in_id', 'eq', $this->warehouse->warehouse_id],
                    ]);
            $this->searchModel($allot, [
                'eq' => ['allot_sn', 'out_id', 'track_num']
            ]);
            $limit = $this->getPageSize();
            $allot = $allot->paginate($limit);
            $this->assign("list", $allot->getCollection());
            $this->assign("page", $allot->render());
            return $this->fetch('allot_lists');
        }
        $this->assign('warehouse', Warehouse::getAll());
        return $this->fetch('allot_index');
    }

    /**
     * 执行调拨单收货
     * @date 2021/02/24
     * @author longli
     */
    public function allot_recv()
    {
        if($this->request->isPost())
        {
            $allotId = $this->request->post('allot_id');
            if(empty($allotId)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
            $allots = WarehouseAllot::whereIn('allot_id', $allotId)->select();
            if($allots->isEmpty()) $this->error("调拨单不存在", '', ["type" => "order-not-exist"]);
            foreach($allots as $allot)
            {
                $allot->status = WarehouseAllot::ALLOT_STATUS_WAIT_UP;
                $allot->save();
            }
            $this->success('收货成功', '', ["type" => "recv-success"]);
        }
        // 显示收货界面
        $sn = $this->request->get('sn', '', 'trim');
        if(empty($sn)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
        $allot = WarehouseAllot::with(['info' => function($query)
        {
            $query->where('qty', 'gt', 0);
        }])->where('allot_sn', $sn)
            ->whereOr('track_num', $sn)
            ->find();
        if(!$allot) $this->error("调拨单不存在", '', ["type" => "order-not-exist"]);
        if($allot->in_id != $this->warehouse->warehouse_id)
            $this->error("调拨单不属于【{$this->warehouse->name}】", '', ["type" => "abnormal-operation"]);
        $this->assign('allot', $allot);
        return $this->fetch('allot_recv');
    }

    /**
     * 订单退货
     * @date 2021/01/21
     * @author longli
     */
    public function order()
    {
        if($this->request->isAjax())
        {
            $order = Orders::with([ 'account'])->where([
                ['order_status', 'in', [Orders::ORDER_RETURN_PART, Orders::ORDER_RETURN]],
                ['send_status', 'in', [Orders::SEND_RETURN_ING]],
            ])->whereIn("order_id", function($query)
            {
                $query->table(OrdersDetail::getTable())
                    ->where('return_qty', 'gt', 0)
                    ->field("order_id");
            })->whereIn('order_id', function($query)
            {
                $query->table(OrdersReturn::getTable())
                    ->where('in_id', $this->warehouse->warehouse_id)
                    ->field("order_id");
            });
            $this->searchModel($order, [
                'eq' => ['order_sn', 'order_no']
            ]);
            $limit = $this->getPageSize();
            $order = $order->paginate($limit);
            $this->assign("list", $order->getCollection());
            $this->assign("page", $order->render());
            return $this->fetch('order_lists');
        }
        return $this->fetch('order_index');
    }

    /**
     * 订单退货收货
     * @date 2021/02/25
     * @author longli
     */
    public function order_recv()
    {
        if($this->request->isPost())
        {
            if($this->request->post('sku'))
            {
                $order = $this->validateOrderRecv();
                $this->updateOrderStatus($order);
                $this->success('收货成功', '', ["type" => "recv-success"]);
            }
            else
            {
                $ids = $this->request->post('ids');
                if(empty($ids)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
                $orders = Orders::with(['detail' => function($query)
                {
                    $query->where([
                        ['return_qty', 'gt', 0],
                        ['is_recv', 'eq', Orders::IS_NO],
                    ]);
                }])->whereIn('order_id', $ids)->select();
                foreach($orders as $order)
                {
                    $this->updateOrderStatus($order);
                }
                $this->success('收货成功', '', ["type" => "recv-success"]);
            }
        }
        $sn = $this->request->get('sn', '', 'trim');
        if(empty($sn)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
        // 如果输入的是追踪号则转成订单号
        if($order = OrdersReturn::get(['track_num' => $sn]))
        {
            $this->assign('track_num', $sn);
            $sn = $order->order->order_sn;
        }
        $order = Orders::with(['detail' => function($query)
        {
            $query->where([
                ['return_qty', 'gt', 0],
                ['is_recv', 'eq', Orders::IS_NO],
            ]);
        }])->whereRaw("order_sn=? OR order_no=?", [$sn, $sn])
           ->find();
        if(!$order) $this->error("订单不存在", '', ["type" => "order-not-exist"]);
        if($order->ren->in_id != $this->warehouse->warehouse_id)
            $this->error("退货订单不属于【{$this->warehouse->name}】", '', ["type" => "abnormal-operation"]);
        $this->assign('order', $order);
        return $this->fetch('order_recv');
    }

    /**
     * 更新订单退货状态
     * @param Orders $order 订单
     * @date 2021/02/26
     * @author longli
     */
    private function updateOrderStatus(Orders $order)
    {
        $order->send_status = $order->isReturnAll()
            ? Orders::SEND_RETURN_ALL
            : Orders::SEND_RETURN_PART;
        $order->save();
        /*foreach($order->detail as $detail)
        {
            if($detail->return_qty < 1) continue;
            $detail->is_recv = Orders::IS_YES;
            $detail->save();
        }*/
    }

    /**
     * 验证订单退货
     * @return Orders
     * @date 2021/02/25
     * @author longli
     */
    private function validateOrderRecv()
    {
        $validate = \think\facade\Validate::make([
            'order_id'  => 'require',
            'sku'  => 'require|array',
            'qty'  => 'require|array',
        ],[
            'order_id.require' => '订单必传',
            'sku.array' => 'SKU 只能是数组',
            'qty.array' => '数量只能是数组',
        ]);
        if(!$validate->batch()->check($this->request->post()))
            $this->error("非法操作", '', ["type" => "abnormal-operation"]);
        $order = Orders::with(["detail" => function($query)
        {
            $query->where('return_qty', 'gt', 0);
        }])->where("order_id", $this->request->post('order_id'))->find();
        if(!$order) $this->error("订单不存在", '', ["type" => "order-not-exist"]);
        $post = $this->request->post();
        foreach($order->detail as $detail)
        {
            foreach($post['sku'] as $k => $sku)
            {
                if($sku == $detail->sku)
                {
                    if(!isset($post['return_qty'][$k]))
                        $this->error("SKU【{$sku}】数量不存在", '', ["type" => "abnormal-operation"]);
                    $qty = intval($post['return_qty'][$k]);
                    if($qty < 1)
                        $this->error("SKU【{$sku}】收货数量不能小于1", '', ["type" => "abnormal-operation"]);
                    if($qty != $detail->return_qty)
                        $this->error("SKU【{$sku}】收货数量必须等于退货数量", '', ["type" => "abnormal-operation"]);
                    break;
                }
            }
        }
        return $order;
    }

    /**
     * 借用商品
     * @date 2021/02/18
     * @author longli
     */
    public function borrow()
    {
        if($this->request->isAjax())
        {
            $borrow = WarehouseBorrow::with(['wout'])->where([
                ['status', 'in', [WarehouseBorrow::STATUS_RETURN_PART, WarehouseBorrow::STATUS_OUT]],
            ]);
            $this->searchModel($borrow, [
               'eq' => ['out_id', 'borrow_sn', 'borrow_date', 'out_date']
            ]);
            $limit = $this->getPageSize();
            $borrow = $borrow->paginate($limit);
            $this->assign("list", $borrow->getCollection());
            $this->assign("page", $borrow->render());
            return $this->fetch('borrow_lists');
        }
        $this->assign('warehouse', Warehouse::getAll());
        return $this->fetch('borrow_index');
    }

    /**
     * 借用收货
     * @date 2021/03/01
     * @author longli
     */
    public function borrow_recv()
    {
        if($this->request->isPost())
        {
            if($this->request->post('sku'))
            {
                $borrow = $this->validateBorrowRecv();
                $this->updateBorrowStatus($borrow, $this->request->post());
            }
            else
            {
                $ids = $this->request->post('ids');
                if(empty($ids)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
                foreach(WarehouseBorrow::whereIn("borrow_id", $ids)->select() as $borrow)
                {
                    $this->updateBorrowStatus($borrow);
                }
            }
            $this->success('收货成功', '', ["type" => "recv-success"]);
        }
        $sn = $this->request->request('borrow_sn', '','trim');
        if(empty($sn)) $this->error("非法操作", '', ["type" => "abnormal-operation"]);
        $borrow = WarehouseBorrow::with(['info' => function($query)
        {
            $query->where('qty', 'gt', Db::raw('in_qty'));
        }])->where('borrow_sn', $sn)->find();
        if(!$borrow) $this->error("借用单不存在", '', ["type" => "order-not-exist"]);
        $this->assign('borrow', $borrow);
        return $this->fetch('borrow_recv');
    }

    /**
     * 更新借用单状态
     * @date 2021/03/01
     * @author longli
     */
    private function updateBorrowStatus(WarehouseBorrow $borrow, $return = [])
    {
        if(!empty($return))
        {
            foreach($return['sku'] as $k => $sku)
            {
                $qty = intval($return['in_qty'][$k]);
                if($qty < 1) continue;
                foreach($borrow->info as $info)
                {
                    if($info->sku == $sku)
                    {
                        if($info->in_qty >= $info->qty) continue;
                        $info->in_qty += $qty;
                        $info->save();
                        break;
                    }
                }
            }
        }
        else
        {
            foreach($borrow->info as $info)
            {
                $info->in_qty = $info->qty;
                $info->save();
            }
        }
        $borrow->status = WarehouseBorrow::isReturnAll($borrow->borrow_id)
            ? WarehouseBorrow::STATUS_RETURN_ALL
            : WarehouseBorrow::STATUS_RETURN_PART;
        $borrow->return_date = Tools::now();
        $borrow->in_id = $this->warehouse->warehouse_id;
        $borrow->save();
    }

    /**
     * 验证借用收货信息
     * @date 2021/03/01
     * @author longli
     */
    private function validateBorrowRecv()
    {
        $validate = \think\facade\Validate::make([
            'borrow_id'  => 'require',
            'sku'  => 'require|array',
            'qty'  => 'require|array',
        ],[
            'borrow_id.require' => '借用单必传',
            'sku.array' => 'SKU 只能是数组',
            'qty.array' => '数量只能是数组',
        ]);
        if(!$validate->batch()->check($this->request->post()))
            $this->error("非法操作", '', ["type" => "abnormal-operation"]);
        $borrow = WarehouseBorrow::with(["info" => function($query)
        {
            $query->where('qty', 'gt', Db::raw('in_qty'));
        }])->where("borrow_id", $this->request->post('borrow_id'))->find();
        if(!$borrow) $this->error("借用单不存在", '', ["type" => "order-not-exist"]);
        $post = $this->request->post();
        foreach($borrow->info as $info)
        {
            foreach($post['sku'] as $k => $sku)
            {
                if($sku == $info->sku)
                {
                    if(!isset($post['in_qty'][$k]))
                        $this->error("SKU【{$sku}】数量不存在", '', ["type" => "abnormal-operation"]);
                    $qty = intval($post['in_qty'][$k]);
                    if($qty < 1)
                        $this->error("SKU【{$sku}】退还数量不能小于1", '', ["type" => "abnormal-operation"]);
                    if($qty > $info->qty)
                        $this->error("SKU【{$sku}】退还数量不能大于借用数量", '', ["type" => "abnormal-operation"]);
                    break;
                }
            }
        }
        return $borrow;
    }
}